package com.ikangtai.shecare.common.util;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Looper;
import android.support.v7.app.AlertDialog;
import android.widget.Toast;

import com.ikangtai.shecare.R;
import com.ikangtai.shecare.common.App;
import com.ikangtai.shecare.common.db.DBManager;
import com.ikangtai.shecare.personal.LoginActivity;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.simple.eventbus.EventBus;

import java.io.IOException;
import java.util.concurrent.TimeUnit;


public class OKHttpUtil {
    private static String buildType;
    private JSONObject jsonObject = new JSONObject();
    private static final OkHttpClient mOkHttpClient = App.getOKHttpClient();
    private Context context;
    private static String openID = null;
    private static DBManager dbManager;
    private Dialog changeDeviceDialog;
    private boolean has215 = false; //防止拦截器多次获取215，弹出对话框

    public OKHttpUtil(Context context) {
        this.context = context;
        buildType = context.getResources().getString(R.string.buildType);
        dbManager = new DBManager(context);
    }

    /**
     *  同步方法  get(String appendUrl);
     *  建议使用异步方法 getAsync(String appendUrl, Callback callback)！
     *  用法：
     *    String authToken = jsonObject.getString("authToken");
     *    String appendUrl = "user/getUserInfo.json?authToken=" + authToken;
     *
     *    try {
     *          OKHttpUtil okHttpUtil = new OKHttpUtil();
     *          okHttpUtil.get(appendUrl);
     *    } catch (JSONException e) { }
     *
     *   返回的结果数据以eventbus的方式获取，可以在获取的地方用@subscriber的方法，接收参数为 EventBusMsg eventBusMsg;
     */
    public void get(String appendUrl){
        OKHttpGetRunnable okHttpGetRunnable = new OKHttpGetRunnable(appendUrl);
        new Thread(okHttpGetRunnable).start();
    }

    public JSONObject add(String key, String value) throws JSONException{
        return jsonObject.put(key, value);
    }

    public JSONObject add(String key, int value) throws JSONException{
        return jsonObject.put(key, value);
    }

    public JSONObject add(String key, JSONObject value) throws JSONException{
        return jsonObject.put(key, value);
    }

    public JSONObject add(String key, JSONArray value) throws JSONException{
        return jsonObject.put(key, value);
    }

    public JSONObject add(String key, double value) throws JSONException{
        return jsonObject.put(key, value);
    }

    /**
     *  同步方法  post(String appendUrl)
     *  建议使用异步方法 postAsync(String appendUrl, Callback callback)！
     *  用法：
     *    String appendUrl = "login/login.json";
     *    OKHttpUtil okHttpUtil = new OKHttpUtil();
     *
     *    try {
     *      okHttpUtil.add("emailOrPhone", "hxiao1983@126.com");
     *      okHttpUtil.add("password", "abcd....");
     *      okHttpUtil.post(url);
     *    }catch (JSONException e) {}
     *
     *  返回的结果数据以eventbus的方式获取，可以在获取的地方用@subscriber的方法，接收参数为 EventBusMsg eventBusMsg;
     */
    public void post(String appendUrl){
        OKHttpPostRunnable okHttpPostRunnable = new OKHttpPostRunnable(appendUrl, jsonObject.toString());
        new Thread(okHttpPostRunnable).start();
    }

    /**
     * 异步方法  getAsync(String appendUrl, Callback callback)
     * 用法：
     *   OKHttpUtil okHttpUtil = new OKHttpUtil();
     *
     *   okHttpUtil.getAsync(appendUrl, new Callback() {
     *      @Override
     *      public void onFailure(Request request, IOException e) {
     *          AppLog.e("okHttpUtil.getAsync failed! request = " + request.urlString());
     *      }
     *
     *      @Override
     *      public void onResponse(Response response) throws IOException {
     *          AppLog.e("okHttpUtil.getAsync success! response = " + response.body().string());
     *      }
     *   });
     *
     * 注意：callback是在异步线程里，因此不要在callback里直接操作view！若要操作view，请用eventbus：
     *  @Override
     *   public void onResponse(Response response) throws IOException {
     *       EventBusMsg eventBusMsg = new EventBusMsg();
     *       eventBusMsg.msgType = "get";
     *       eventBusMsg.message = response.body().string();
     *       EventBus.getDefault().post(eventBusMsg);
     *   }
     *   然后捕捉：
     *   @Subcriber
     *   private void updateTextView(EventBusMsg eventBusMsg) {
     *   String msgType = eventBusMsg.msgType;
     *   String message = eventBusMsg.message;
     *
     *   if(msgType.equals("get")){
     *      AppLog.e("I AM GET2: " + message);
     *      tv.setText(message);
     *   }
     *   else {}
     */
    public void getAsync(String appendUrl, Callback callback){
        AppLog.e("getAsync: " + appendUrl);
        String finalUrl = App.baseUrlPath + appendUrl;
        Request request = new Request.Builder()
                                .url(finalUrl)
                                .build();
        mOkHttpClient.setConnectTimeout(App.HTTP_CONNECT_TIMEOUT, TimeUnit.SECONDS);
        mOkHttpClient.setWriteTimeout(App.HTTP_READ_WRITE_TIMEOUT, TimeUnit.SECONDS);
        mOkHttpClient.setReadTimeout(App.HTTP_READ_WRITE_TIMEOUT, TimeUnit.SECONDS);
        mOkHttpClient.interceptors().add(new ResponseCodeInterceptor());
        mOkHttpClient.newCall(request).enqueue(callback);
    }

    /**
     * 异步方法  postAsync(String appendUrl, Callback callback)
     * 用法：
     *   OKHttpUtil okHttpUtil = new OKHttpUtil();
     *   try {
     *      okHttpUtil.add("emailOrPhone", "hxiao1983@126.com");
     *      okHttpUtil.add("password", "abcd....");
     *      okHttpUtil.postAsync(appendUrl, new Callback() {
     *          @Override
     *          public void onFailure(Request request, IOException e) {
     *              AppLog.e("okHttpUtil.getAsync failed! request = " + request.urlString());
     *          }
     *
     *          @Override
     *          public void onResponse(Response response) throws IOException {
     *              AppLog.e("okHttpUtil.getAsync success! response = " + response.body().string());
     *          }
     *      });
     *   }catch (JSONException e) {}
     *
     *   注意：callback是在异步线程里，因此不要在callback里直接操作view！方法同getAsync
     */
    public void postAsync(String appendUrl, Callback callback){
        AppLog.e("postAsync: " + appendUrl);
        String finalUrl = App.baseUrlPath + appendUrl;
        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(JSON, jsonObject.toString());

        Request request = new Request.Builder()
                                .url(finalUrl)
                                .post(body)
                                .build();
        mOkHttpClient.setConnectTimeout(App.HTTP_CONNECT_TIMEOUT, TimeUnit.SECONDS);
        mOkHttpClient.setWriteTimeout(App.HTTP_READ_WRITE_TIMEOUT, TimeUnit.SECONDS);
        mOkHttpClient.setReadTimeout(App.HTTP_READ_WRITE_TIMEOUT, TimeUnit.SECONDS);
        mOkHttpClient.interceptors().add(new ResponseCodeInterceptor());
        mOkHttpClient.newCall(request).enqueue(callback);
    }

    private class OKHttpGetRunnable implements Runnable{
        private final OkHttpClient mOkHttpClient = App.getOKHttpClient();
        private String finalUrl;

        OKHttpGetRunnable(String appendUrl){
            finalUrl = App.baseUrlPath + appendUrl;
        }

        @Override
        public void run() {
            Request request = new Request.Builder()
                    .url(finalUrl)
                    .build();

            try {
                Response response = mOkHttpClient.newCall(request).execute();
                EventBusMsg eventBusMsg = new EventBusMsg();
                eventBusMsg.msgType = "get";
                eventBusMsg.message = response.body().string();
                AppLog.e("get: " + eventBusMsg.message);

                if(response.isSuccessful())
                    EventBus.getDefault().post(eventBusMsg);
                else
                    throw new IOException("request failed:" + response);


            }catch(IOException e){}
        }
    }

    private class OKHttpPostRunnable implements Runnable{
        private final OkHttpClient mOkHttpClient = App.getOKHttpClient();
        private final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        private String finalUrl;
        String bodyJsonStr;

        OKHttpPostRunnable(String appendUrl, String bodyJsonStr){
            finalUrl = App.baseUrlPath + appendUrl;
            this.bodyJsonStr = bodyJsonStr;
        }

        @Override
        public void run() {
            RequestBody body = RequestBody.create(JSON, bodyJsonStr);
            Request request = new Request.Builder()
                                    .url(finalUrl)
                                    .post(body)
                                    .build();

            try {
                Response response = mOkHttpClient.newCall(request).execute();
                EventBusMsg eventBusMsg = new EventBusMsg();
                eventBusMsg.msgType = "post";
                eventBusMsg.message = response.body().string();
                AppLog.e("post: " + eventBusMsg.message);

                if(response.isSuccessful())
                    EventBus.getDefault().post(eventBusMsg);
                else
                    throw new IOException("request failed:" + response);

            }catch(IOException e){

            }
        }
    }

    class ResponseCodeInterceptor implements Interceptor{
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            AppLog.i("begin intercept! request = " + request.urlString());
            Response response = chain.proceed(request);

            MediaType mediaType = response.body().contentType();

            try {
                final String content = response.body().string();
                AppLog.i("intercept! str = " + content);

                JSONObject respJSONObj = new JSONObject(content);
                int respCode = respJSONObj.getInt("code");

                if(respCode == 215){
                    // 会连续收到2次请求，故同步一下，否则会生成2个changeDeviceDialog，
                    // 这里为了保证changeDeviceDialog的唯一性，否则再次登陆进来仍会看到另外一个changeDeviceDialog
                    synchronized (Dialog.class) {
                        if(!has215) {
                            AppLog.i("receive 215 in intercept! logout!");
                            String alertTitle = "通知";
                            String alertMsg = "你的账号正在另外一台设备登陆, 请重新登陆!";
                            String updateAlertPositiveButtonTxt = "确定";

                            Looper.prepare();

                            if (changeDeviceDialog == null) {
                                changeDeviceDialog = new AlertDialog.Builder(context).setTitle(alertTitle)
                                        .setMessage(alertMsg)
                                        .setCancelable(false)
                                        .setPositiveButton(updateAlertPositiveButtonTxt, new DialogInterface.OnClickListener() {
                                                    @Override
                                                    public void onClick(DialogInterface dialog, int which) {
                                                        dialog.dismiss();
                                                        Intent intent = new Intent(context, LoginActivity.class);
                                                        context.startActivity(intent);
                                                    }
                                                }
                                        ).create();
                                changeDeviceDialog.show();
                                has215 = true;
                            }

                            Looper.loop();
                        }
                    }
                }

                response = response.newBuilder().body(ResponseBody.create(mediaType, content)).build();

            }catch (IllegalStateException e){
                    AppLog.e("IllegalStateException! e = " + e.getMessage());
            }catch (JSONException e){
                AppLog.e("JSONException");
            }catch (Exception e){
                    AppLog.e("Exception");
            }

            AppLog.i("end intercept! request = " + request.urlString());
            return response;
        }
    }

    public static void setNewToken(){
        AppLog.i("begin get new token! old Token = " + App.authToken);

        String appendUrl;
        if (buildType.equals("god"))
            appendUrl = "login/internal.json";
        else
            appendUrl = "login/login.json";

        String url = App.baseUrlPath + appendUrl;
        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        JSONObject jsonObject = new JSONObject();

        try{
            jsonObject.put("emailOrPhone", App.userName);

            if (!buildType.equals("god")) {
                jsonObject.put("password", App.userPswd);

                String phoneID = DeviceInfo.getDeviceID();
                jsonObject.put("phoneID", phoneID);
            }

            openID = dbManager.getSqliteKeyValue(App.userName, "openID");
            if(!(openID == null || openID.length()<=0)){
                jsonObject.put("serviceID", openID);
            }

            RequestBody body = RequestBody.create(JSON, jsonObject.toString());

            Request request = new Request.Builder().url(url).post(body).build();

            Response response = mOkHttpClient.newCall(request).execute();
            String respStr = response.body().string();

            JSONObject respJSONObj = new JSONObject(respStr);
            int respCode = respJSONObj.getInt("code");

            if(respCode == 200) {
                String newToken = respJSONObj.getString("authToken");
                App.authToken = newToken;
                App.saveUserPreference(App.SHARED_PREF_USER_TOKEN, App.authToken);
                AppLog.i("get new token! new Token = " + App.authToken);
            }else{
                AppLog.i("get new token, but got error respCode = " + respCode);
            }
        }catch (IOException e){
            AppLog.i("IOException! e = " + e.getMessage());
        }catch(JSONException e){
            AppLog.e("JSONException! e = " + e.getMessage());
        }catch (Exception e){
            AppLog.i("Exception! e = " + e.getMessage());
        }

        AppLog.i("get new token end! ");
    }

    public class BaseCallBack implements Callback {
        @Override
        public void onFailure(Request request, IOException e) {
            AppLog.i("OKHttpUtil Callback onFailure! request = " + request.urlString());
            e.printStackTrace();

            Looper.prepare();
            Toast.makeText(context, "网络异常, 请检查网络!", Toast.LENGTH_SHORT).show();
            Looper.loop();
        }

        @Override
        public void onResponse(Response response) throws IOException {

        }
    }

}
